
# -*- coding: utf-8 -*-
#  F7帮助
# @Time    ： 2024/7/17  22:54
# @Auther  ： 徐良
# File     :  f7LineEdits.py
from typing import Dict, Any
from PySide6 import QtWidgets
from PySide6.QtGui import QPalette, QKeyEvent
from PySide6.QtWidgets import QLineEdit
from PySide6.QtCore import Signal, QSize, QEvent
from baseClass.tools.strFunction import quote, get_list_from_str_by_pipe
from baseClass.business.sqlParseTool import SqlParseTool
# from mesParts.component.makeF7help import MakeF7help
# from mesParts.component.f7EditPanel import F7EditPanel
# from mesParts.component.f7SimplePanel import F7SimplePanel
# from mesParts.component.f7EditAlonePanel import F7EditAlonePanel


import re
import logging

css1 = ("""
    /* 设置文本框背景颜色 */
    QLineEdit {
        background-color: #f0f0f0;
        border: 2px solid #ccc;  /* 设置边框 */
        border-radius: 5px;  /* 设置边框圆角 */
        padding: 5px;  /* 设置内边距 */
        font-size: 14px;  /* 设置字体大小 */
    }

    /* 设置文本框激活状态下的边框颜色 */
    QLineEdit:focus {
        border-color: #0078d7;
    }

    /* 设置文本框内部的光标颜色 */
    QLineEdit::cursor {
        width: 2px;  /* 光标宽度 */
        background-color: #0078d7;  /* 光标颜色 */
    }

    /* 设置文本框中的文字颜色 */
    QLineEdit::placeholder {
        color: #999;  /* 文字颜色 */
    }
""")

def get_sql(s, v):
    swd = SqlParseTool.get_swo(s)
    s = swd['s']
    r = re.search(r'a\.\w{2,}', s)
    if r is None:
        ss = s + ' where FNumber=' + quote(v)
    else:
        ss = s + ' where a.FNumber=' + quote(v)
    return ss


def get_value_list(sSql: str, fieldList: list, typeList: list) -> list:
    """
    从数据库记录中读取指定字段的值

    Args:
        sSql: SQL查询语句
        fieldList: 需要获取的字段名列表
        typeList: 对应字段的类型列表(与fieldList长度一致)

    Returns:
        包含各字段值的列表，如果没有记录则返回与fieldList长度相同的空字符串列表

    Raises:
        ValueError: 如果fieldList和typeList长度不一致
    """
    # 参数校验
    if len(fieldList) != len(typeList):
        raise ValueError("fieldList and typeList must have the same length")

    # 执行查询
    model = DataFactory.get_query_model_by_sql(sSql)

    # 无数据情况直接返回预设结果
    if model.rowCount() == 0:
        return [''] * len(fieldList)

    # 获取第一条记录
    record = model.record(0)
    result = []

    # 处理每个字段
    for field, field_type in zip(fieldList, typeList):
        value = record.value(field)

        # 类型转换处理
        if field_type.lower() == 'integer':
            value = str(value)
        elif value is None:  # 处理NULL值情况
            value = ''

        result.append(value)

    return result

class F7EditBase(QLineEdit):
    """
    F7Edit  2 个参数 (字典 + 父对象)。
    """
    f7RetComplete = Signal(str)  # 发出接收处理成功的信号
    textChangedSignal = Signal(object)  # 传递本控件

    def __init__(self, parent=None, **kwargs: Dict[str, Any]):
        """
        F7帮助基类
        :param parent: 父类
        :param kwargs: 参数
        """
        super().__init__(parent)
        self.work = kwargs.get("work")
        if self.work is None:
            logging.error("work 参数未提供，BaseLineEdit 初始化失败")
            raise ValueError("work 参数是必选的")

        self.ROB = 0
        self.number = ''
        self.name = ''

        self.correct = 0       # 是否正确标志，0 不正确， 1正确

        self.f7_panel = None
        self.valueList = None
        self.retValueList = None
        self.retTypeList = None
        self.retFieldList = None
   
        self.f7_panel = None

        # 获取系统默认的文本颜色
        self.default_color = self.palette().color(QPalette.ColorRole.Text).name()
        self.update_color()  # 初始化颜色

        self.returnPressed.connect(self.on_enter_return)
        # 连接编辑状态改变的信号槽
        self.textChanged.connect(self.on_text_changed)

        self.textEdited.connect(self.on_editing)

    def set_rob(self, value):
        if self.ROB != value:
            self.ROB = value
            self.update_color()  # 更新颜色

    def update_color(self):
        """根据 self.ROB 的值更新字体颜色"""
        if self.ROB == 1:
            self.setStyleSheet("color: red;")
        else:
            self.setStyleSheet(f"color: {self.default_color};")

    def keyPressEvent(self, event):

        if event.key() == Qt.Key.Key_F7:

            dic = {'obj': self, 'work': self.work, 'objectName': self.objectName(),
                   'panelStyle': 'Edit', 'index': None}

            f7help = MakeF7help(**dic)
            self.f7_panel = F7EditPanel(f7help.para_map)
            self.f7_panel.F7PanelRetSignal.connect(self.on_f7_ret)
            self.f7_panel.show()
        else:
            super().keyPressEvent(event)  # 调用父类的键盘事件处理

    def focus_next_child(self, obj):
        o = self.get_next_obj(obj)
        if o is not None:
            o.setFocus()

    def get_next_obj(self, obj):
        if self.work.WORK_CLASS_NAME == '独立表':
            objs = self.work.f_obj_list
        else:
            objs = self.work.h_obj_list
        count = len(objs)
        ret = -1
        for i in range(0, count):
            if objs[i] is not None:
                if obj.objectName() == objs[i].objectName():
                    ret = i
                    break

        if ret == -1:
            return obj

        r = ret + 1
        for i in range(r, count):
            if objs[i].isEnabled():
                return objs[i]

        for i in range(0, ret):
            if objs[i].isEnabled():
                return objs[i]

    def get_obj(self, field):
        ret = None
        if self.work.WORK_CLASS_NAME == '独立表':
            obj_list = self.work.f_obj_list
        else:
            obj_list = self.work.h_obj_list

        for obj in obj_list:
            if obj is not None:
                if obj.objectName().lower() == field.lower().strip():
                    ret = obj
                    break
        return ret

    def set_value_for_Obj(self, field_list, value_list, type_list):
        """
        根据字段名，设置返回值
        :param type_list: 数据类型
        :param field_list: 字段列表
        :param value_list: 值列表
        :return:
        """
        for f, v, t in zip(field_list, value_list, type_list):
            obj = self.get_obj(f)
            if obj is not None:
                if t.lower() == 'integer':
                    obj.setText(str(v))
                else:
                    obj.setText(v)

    def set_obj_value(self, s_field, s_value):
        """
        返回值赋给控件，不能用self
        :param s_value:
        :param s_field:
        :return:
        """

        obj = self.get_obj(s_field)
        if obj is not None:
            obj.setText(s_value)

    def on_enter_return(self):
        pass

    def on_f7_ret(self, dic=None):
        pass

    def on_editing(self):
        self.correct = 2

    def on_text_changed(self, text):
        """文本变化时触发信号"""
        self.textChangedSignal.emit(self)


class F7NumberEdit(F7EditBase):
    """
    根据代码获取相关字段数据
    """
    dateChangedSignal = Signal(str)
    def __init__(self, parent=None, **kwargs: Dict[str, Any]):
        """
        F7帮助代码-其他附带项
        :param parent: 父类
        :param kwargs: 参数
        """
        super().__init__(**kwargs)
        self.setFieldList = None
        self.getFieldList = None

    def keyPressEvent(self, event):

        if event.key() == Qt.Key.Key_F7:

            dic = {'obj': self, 'work': self.work, 'objectName': self.objectName(),
                   'panelStyle': 'Edit', 'index': None}

            f7help = MakeF7help(**dic)
            self.f7_panel = F7EditPanel(f7help.para_map)
            self.f7_panel.F7PanelRetSignal.connect(self.on_f7_ret)
            self.f7_panel.show()
        else:
            super().keyPressEvent(event)  # 调用父类的键盘事件处理
            # 手动重新发送事件
            # QApplication.postEvent(self, event)

    def on_f7_ret(self, dic=None):
        # 处理界面显示
        self.retFieldList = dic['retFieldList']
        self.valueList = dic['retValueList']
        self.retTypeList = dic['fieldTypeList']
        obj = dic['obj']
        #设置控件的返回值
        for field, value, stype in zip(self.retFieldList, self.valueList, self.retTypeList):
            if stype.lower() == 'integer':
                self.set_obj_value(field, str(value))
            else:
                self.set_obj_value(field, value)

        self.dateChangedSignal.emit('yes')
        self.textChangedSignal.emit(self)
        self.correct = 1
        if hasattr(self, 'label'):
            self.label.removeError()
        self.focus_next_child(obj)

    def on_enter_return(self):
        obj = self.sender()
        if self.work.WORK_CLASS_NAME == '独立表':
            num = self.work.get_f_column_by_field_name(self.objectName())
            relationTableList = get_list_from_str_by_pipe(self.work.f_relation_table_list[num])
            relationGetAndRetList = get_list_from_str_by_pipe(self.work.f_relation_get_ret_list[num])
        else:
            num = self.work.get_h_column_by_field_name(self.objectName())
            relationTableList = get_list_from_str_by_pipe(self.work.h_relation_table_list[num])
            relationGetAndRetList = get_list_from_str_by_pipe(self.work.h_relation_get_ret_list[num])

        sql = relationTableList[4]
        self.getFieldList = relationGetAndRetList[0].split(',')
        self.retTypeList = relationGetAndRetList[1].split(',')
        self.setFieldList = relationGetAndRetList[2].split(',')

        value = obj.text()
        sql = get_sql(sql, value)

        self.valueList = get_value_list(sql, self.getFieldList, self.retTypeList)

        self.set_value_for_Obj(self.setFieldList, self.valueList, self.retTypeList)

        self.work.mapper.submit()

        self.textChangedSignal.emit(self)
        self.correct = 1
        if hasattr(self, 'label'):
            self.label.removeError()
        self.focus_next_child(obj)


class F7NameEdit(F7EditBase):
    """
    代码和名称的帮助，只有两个数据
    self.valueList = None, 空返回， ['001', 'abc']
    """
    dateChangedSignal = Signal(str)
    def __init__(self, parent=None, **kwargs: Dict[str, Any]):
        """
        F7帮助代码-其他附带项
        :param parent: 父类
        :param kwargs: 参数
        """
        super().__init__(**kwargs)
        self.setFieldList = None
        self.getFieldList = None
        self.correct = 0

    def focusInEvent(self, e):
        self.setText(self.number)
        QtWidgets.QLineEdit.focusInEvent(self, e)

    def focusOutEvent(self, e):
        """
        失去焦点
        :param e:
        :return:
        """
        if self.correct == 1:
            self.setText(self.name)
        QtWidgets.QLineEdit.focusOutEvent(self, e)

    def on_f7_ret(self, dic=None):
        """
        处理界面显示, 必须使用控件，不可以用self
        只需处理返回数据，第1列是代码，第2列是名称
        得到焦点是显示代码，否则显示名称
        :param dic:
        :return:
        """
        self.valueList = dic['retValueList']
        obj = dic['obj']
        if obj is not None:
            obj.number = self.valueList[0]
            obj.name = self.valueList[1]
            obj.setText(self.valueList[1])

        self.dateChangedSignal.emit('yes')
        self.textChangedSignal.emit(self)
        self.correct = 1
        self.focus_next_child(dic['obj'])

    def on_enter_return(self):
        """
        按回车事件事件
        :return:
        """
        obj = self.sender()
        if self.work.WORK_CLASS_NAME == '独立表':
            num = self.work.f_field_list.index(self.objectName())
            relationTableList = get_list_from_str_by_pipe(self.work.f_relation_table_list[num])
            relationGetAndRetList = get_list_from_str_by_pipe(self.work.f_relation_get_ret_list[num])
        else:
            num = self.work.h_field_list.index(self.objectName())
            relationTableList = get_list_from_str_by_pipe(self.work.h_relation_table_list[num])
            relationGetAndRetList = get_list_from_str_by_pipe(self.work.h_relation_get_ret_list[num])

        sql = relationTableList[4]
        self.getFieldList = relationGetAndRetList[0].split(',')
        self.retTypeList = relationGetAndRetList[1].split(',')
        self.setFieldList = relationGetAndRetList[2].split(',')

        value =  obj.text()
        sql = get_sql(sql, value)

        self.valueList = get_value_list(sql, self.getFieldList, self.retTypeList)
        obj.number = self.valueList[0]
        obj.name = self.valueList[1]
        obj.setText(self.valueList[1])
        self.textChangedSignal.emit(self)
        self.correct = 1
        self.focus_next_child(obj)


class F7BodyHelp(F7EditBase):
    """
    用于表体的帮助
    """
    dateChangedSignal = Signal(str)
    def __init__(self,**kwargs: Dict[str, Any]):
        """
        F7帮助代码-其他附带项
        :param parent: 父类
        :param kwargs: 参数
        """
        super().__init__(**kwargs)
        self.getFieldList = None
        self.work = kwargs.get("work")
        self.tableView = kwargs.get("tableView")
        self.field_info = kwargs.get("field_info", {})
        self.setPlaceholderText(self.field_info.get('placeHolderText', ''))

    def keyPressEvent(self, event):
        if event.key() == Qt.Key.Key_F7:
            # 关闭旧面板，避免内存泄漏
            if hasattr(self, 'f7_panel') and self.f7_panel and not self.f7_panel.isHidden():
                self.f7_panel.close()

            # 实时获取当前索引（确保时效性）
            current_index = self.tableView.currentIndex()
            dic = {
                'obj': self,
                'work': self.work,
                'objectName': self.objectName(),
                'panelStyle': 'Grid',
                'gridCol': current_index.column(),
                'index': current_index
            }

            f7help = MakeF7help(**dic)
            self.f7_panel = F7EditPanel(f7help.para_map)
            self.f7_panel.F7PanelRetSignal.connect(self.tableView.onF7ret)
            self.f7_panel.show()
        else:
            # 其他按键交给基类处理（保证文本输入等功能正常）
            super().keyPressEvent(event)


    def on_enter_return(self):
        value = self.text()
        index = self.tableView.currentIndex()
        change_row = index.row()
        if self.work.WORK_CLASS_NAME == '独立表':
            relationTableList = get_list_from_str_by_pipe(self.work.get_f_relation_table_list(index.column()))
            relationGetAndRetList = get_list_from_str_by_pipe(self.work.get_f_relation_get_and_ret_list(index.column()))
        else:
            relationTableList = get_list_from_str_by_pipe(self.work.get_b_relation_table_list(index.column()))
            relationGetAndRetList = get_list_from_str_by_pipe(self.work.get_b_relation_get_and_ret_list(index.column()))

        sql = relationTableList[4]

        self.getFieldList = relationGetAndRetList[0].split(',')
        self.retTypeList = relationGetAndRetList[1].split(',')
        self.retFieldList = relationGetAndRetList[2].split(',')

        sql = get_sql(sql, value)

        self.valueList = get_value_list(sql, self.getFieldList, self.retTypeList)

        model = self.tableView.model()
        for field, value in zip(self.retFieldList, self.valueList):
            if self.work.WORK_CLASS_NAME == '独立表':
                col = self.work.get_f_field_column(field)
            else:
                col = self.work.get_b_field_column(field)
            idx = model.index(index.row(), col)
            model.setData(idx, str(value))

        # 判断是否为业务逻辑的开关
        current_delegate = self.tableView.itemDelegate()
        if current_delegate is not None:  # 首先检查代理是否存在
            if hasattr(current_delegate, 'logicSwitch'):
                index = self.tableView.currentIndex()
                current_delegate.mesDataChanged.emit(index.row(),index.column(), current_delegate.logicSwitch)

        # 正确的f7返回需要缓存
        self.work.handel_f7_enter_return(self.retFieldList, self.valueList)

        self.tableView.onF7Return(change_row)



from PySide6.QtWidgets import QLineEdit
from PySide6.QtCore import Qt, Signal
from typing import Dict, Any


class F7SimpleFormEdt(QLineEdit):
    """
    不带树结构，单表F7帮助面板
    完全禁止键盘输入，只能通过F7键调出面板输入内容或程序赋值
    """
    textChangedSignal = Signal(object)  # 传递本控件

    def __init__(self, parent=None, **kwargs: Dict[str, Any]):
        super().__init__(parent)
        self.panel = None
        self.work = kwargs.get('work')
        self._is_programmatic_change = False  # 标记是否为程序赋值

        # 初始设置为只读
        self.setReadOnly(True)
        self.allowEdit = True
        self.setPlaceholderText("按F7键选择内容")

    def setText(self, text: str) -> None:
        """重写setText方法，允许程序赋值"""
        self._is_programmatic_change = True
        super().setText(text)
        self._is_programmatic_change = False
        self.textChangedSignal.emit(self)  # 触发信号

    def keyPressEvent(self, event):
        if not self.allowEdit:
            event.ignore()
            return

        if event.key() == Qt.Key.Key_F7:
            # 保存当前只读状态
            was_readonly = self.isReadOnly()

            # 临时允许编辑（如果需要）
            self.setReadOnly(False)

            # 创建并显示面板
            dic = {'obj': self, 'objectName': self.objectName(), 'work': self.work}
            self.panel = F7SimplePanel(dic)
            self.panel.show()

            # 恢复原来的只读状态
            self.setReadOnly(was_readonly)
        else:
            # 拦截所有其他按键，不调用父类方法
            event.ignore()

    def mousePressEvent(self, event):
        """点击时也触发F7面板"""
        if not self.allowEdit:
            event.ignore()
            return

        if event.button() == Qt.LeftButton:
            self.keyPressEvent(QKeyEvent(QEvent.KeyPress, Qt.Key.Key_F7, Qt.NoModifier))
        else:
            super().mousePressEvent(event)

    def focusOutEvent(self, event):
        # 失去焦点时恢复只读状态（仅限非程序赋值）
        if not self._is_programmatic_change:
            self.setReadOnly(True)
        super().focusOutEvent(event)


class F7SimpleGridEdt(QLineEdit):
    """
    不带树结构，单表F7帮助面板
    """
    def __init__(self, parent=None, **kwargs: Dict[str, Any]):

        super().__init__(parent)

        self.panel = None
        self.valueList = None
        self.retFieldList = None
        self.retTypeList = None
        self.getFieldList = None
        self.tableWork = kwargs.get("tableWork")
        self.tableV = kwargs.get("tableV")
        self.index = kwargs.get("index")
        self.f7dict = kwargs.get("f7dict")
        self.tableFName = kwargs.get("tableFName")


    def keyPressEvent(self, event):

        if event.key() == Qt.Key.Key_F7:
            # obj 必须要加，否则帮助面板会无法显示，可能是因为代理中editor失去焦点后释放内存的原因
            dic = {'obj': self, 'objectName': self.objectName(), 'panelStyle': 'SingleGrid',
                   'tableWork': self.tableWork, 'f7dict': self.f7dict}
            self.panel = F7SimplePanel(dic)
            self.panel.F7PanelRetSignal.connect(self.tableV.onF7ret)
            self.panel.show()
        else:
            super().keyPressEvent(event)  # 调用父类的键盘事件处理

    def onEnterReturn(self):
        value = self.text()
        if value == '':
            return

        index = self.index

        self.getFieldList = self.f7dict['getFieldList']
        self.retTypeList = self.f7dict['fieldTypeList']
        self.retFieldList = self.f7dict['retFieldList']

        whereField = self.f7dict['whereField']
        swd = SqlFunction.get_swo(self.f7dict['searchSql'])
        s = swd['s']
        r = re.search(r'a\.\w{2,}', s)
        if r is None:
            sql = s + ' where ' + whereField + '=' + quote(value)
        else:
            sql = s + ' where a.' + whereField + '=' + quote(value)

        self.valueList = self.__get_value_list(sql, self.getFieldList, self.retTypeList)
        model = self.tableV.model()
        for field, value in zip(self.retFieldList, self.valueList):
            col = self.tableWork.getColByField(self.tableFName, field)
            idx = model.index(index.row(), col)
            model.setData(idx, str(value))

        self.tableV.goNextColumn(index)

    @staticmethod
    def __getStr(ss):
        return ss.replace('#', '').replace('\n', '').replace('*', '').strip()  # 清除#

    @staticmethod
    def __get_value_list(sSql, fieldList, typeList):
        """
        从数据库记录中读取指定字段的值

        Args:
            sSql (str): SQL查询语句
            fieldList (list): 字段名列表
            typeList (list): 字段类型列表(与fieldList一一对应)

        Returns:
            list: 包含各字段值的列表，如果没有记录则返回空字符串列表
        """
        model = DataFactory.get_query_model_by_sql(sSql)
        rows = model.rowCount()

        if rows == 0:
            return [''] * len(fieldList)

        record = model.record(0)
        result = []

        for field, field_type in zip(fieldList, typeList):
            value = record.value(field)
            if field_type.lower() == 'integer':
                value = str(value)
            result.append(value)

        return result


class F7EditAlone(QLineEdit):
    """
    仅发出信号， 不带work
    """
    F7RetSignal = Signal(dict)  # F7帮助面板发出的返回信号，dict = self.retMap

    def __init__(self, parent=None):
        super().__init__()
        self.panel = None
        self.setMinimumSize(QSize(120, 16777215))
        self.golF7Dic = 'F7MaterialDict'    # 默认是物料帮助， 全程变量
        self.number = None
        self.name = ''
        self.valueList = None
        self.retValueList = None
        self.retTypeList = None
        self.setStyleSheet(css1)

    def keyPressEvent(self, event):
        QtWidgets.QLineEdit.keyPressEvent(self, event)

        if event.key() == Qt.Key.Key_F7:
            self.panel = F7EditAlonePanel(self.golF7Dic)
            self.panel.F7PanelRetSignal.connect(self.onF7EditAloneRet)
            self.panel.show()

    def onF7EditAloneRet(self, retMap):
        """
        这个名称一定要取比较特殊一点，避免重复，否则会报错
        :param retMap:
        :return:
        """
        self.F7RetSignal.emit(retMap)